//08290016
#include "dbClass.hpp"
#include "ctcpserver.hpp"
#include "json.hpp"
#include <time.h>
#include <map>
#include <list>
#include <fstream>

#define DATABASE_OK 0

using json = nlohmann::json;

extern map<string, long int> onlineUser;
extern list<json> userOperList;

struct file_transmit_t{
    uint16_t save_cmd; // 保存文件时下一个包的命令该是什么
    string save_name;  // 保存文件名
    ofstream f_save;   // 保存文件的文件写
    uint16_t send_cmd; // 发送本地文件的，同上
    string send_name;
    ifstream f_send;
};
extern map<string, file_transmit_t> userTemp;//存储用户临时信息，与uid一一对应
// int sendPackage(const string& buffer,const uint16_t cmd,int fd)

void pHeartBeat(int fd, json &params)
{
    if (params.is_null())
    {
        cout << "empty pamera\n";
        sendPackage(string(""), 0x41, fd);
        return;
    }
    dbClass dbC(true);
    json rtn_package;
    //获取新消息
    vector<vector<string>> messages = dbC.GetNewMessage(string(params["UID"]), string(params["last_message_id"]));
    vector<vector<string>> addGroupList = dbC.GetNewGroup(string(params["UID"]),string(params["last_group_id"]));
    if (!messages.empty())
    {
        json message_pack,file_message_pack;
        for (auto m : messages)
        {
            if (string(m[6]) == "0")
            {
                json m_data;
                m_data["TID"] = m[0];
                m_data["RID"] = m[2];
                m_data["MID"] = m[3];
                m_data["content"] = m[4];
                m_data["time"] = m[5];
                
                message_pack.push_back(m_data);
            }
            else if (string(m[6]) == "1")
            {
                json f_data;
                f_data["TID"] = m[0];
                f_data["RID"] = m[2];
                f_data["MID"] = m[3];
                f_data["content"] = m[4];
                f_data["time"] = m[5];

                file_message_pack.push_back(f_data);
            }
        }
        if (!message_pack.is_null())
        {
            rtn_package["message"] = message_pack;
        }
        if (!file_message_pack.is_null())
        {
            rtn_package["file"] = file_message_pack;
        }
    }
    if (!addGroupList.empty())
    {
        json group_pack;
        for (auto g : addGroupList)
        {
            json g_data;
            g_data["operator"] = "add";
            g_data["id"] = g[0];
            g_data["name"] = g[1];
            g_data["category"] = g[2];
            group_pack.push_back(g_data);
        }
        if (!group_pack.is_null())
        {
            rtn_package["grouplist"] = group_pack;
        }
    }
    //获取新联系人
    if(params.contains("last_user_id") && params["last_user_id"]<userOperList.size()){
        json user_pack;
        auto pack = userOperList.end(); 
        for(int i = params["last_user_id"];i<userOperList.size();i++,pack--){
            user_pack.push_back(*pack);
        }
        if (!user_pack.is_null())
        {
            rtn_package["userlist"] = user_pack;
        }
    }
    //TODO:好像没有返回新好友
    sendPackage(string(rtn_package.dump(4)), 0x41, fd);
    // "last_user_id":2,
    // "last_group_id":3
}

void pRegister(int fd, json &params)
{
    json rtn, rtn_data;
    if (params.is_null())
    {
        cout << "empty pamera\n";
        return;
    }
    try
    {
        dbClass dbC(true);
        string uid = dbC.AddUser(params["name"], params["password"], "stu");

        rtn_data["UID"] = uid;
        rtn["status"] = "successs";
        rtn["data"] = rtn_data;

        json changePack;
        changePack["UID"] = params["UID"];
        changePack["operator"] = "add";
        changePack["name"] = params["name"];
        changePack["job"] = params["stu"];
        changePack["list_no"] = userOperList.size()+1;
        userOperList.push_back(changePack);
    }
    catch (...)
    {
        cout << "catch error" << endl;
    }
    sendPackage(string(rtn.dump(4)), 0x34, fd);
}

void pRelogin(int fd, json &params)
{
    sendPackage(string("The current device is offline, please log in again."), 0x30, fd);
    return;
}

void pLogin(int fd, json &params)
{
    // 参数非空
    if (params.is_null())
    {
        cout << "empty pamera\n";
        return;
    }
    json rtn_package;
    try
    {
        if (onlineUser.count(params["UID"]) == 0)
        {                      // 如果未登录
            dbClass dbC(true); // 连接数据库
            int rtn_signin = dbC.CheckSignin(params["UID"], params["password"]);
            if (rtn_signin == 0)
            { // 如果登录成功
                rtn_package["result"] = "success";
                onlineUser[string(params["UID"])] = time(0); // 添加到在线池中
                if (dbC.AlterUserIP(params["UID"], params["ip"]) != 0)
                { // IP写入数据库
                    throw -1;
                }
                json changePack;
                changePack["UID"] = params["UID"];
                changePack["operator"] = "online";
                changePack["ip"] = params["ip"];
                changePack["list_no"] = userOperList.size()+1;
                userOperList.push_back(changePack);
                // 获取用户列表
                json rtn_userList;
                try
                {
                    vector<vector<string>> dbC_userlist = dbC.GetUserList();
                    for (auto user : dbC_userlist)
                    {
                        json tmp_json;
                        tmp_json["ip"] = string(user[2]) == "0" ? "-1" : string(user[2]);
                        tmp_json["name"] = user[1];
                        tmp_json["uid"] = user[0];
                        tmp_json["job"] = user[3];
                        rtn_userList.push_back(tmp_json);
                    }
                    rtn_package["userlist"] = rtn_userList;
                    rtn_package["userlist_edition"] = userOperList.size();
                }
                catch (...)
                {
                    cout << "获取用户列表错误\n";
                }
                // 获取群聊列表
                json rtn_groupList;
                try
                {
                    vector<vector<string>> dbC_grouplist = dbC.GetChatGroupList(params["UID"]);
                    for (auto group : dbC_grouplist)
                    {
                        json tmp_json;
                        tmp_json["name"] = group[1];
                        tmp_json["uid"] = group[0];
                        tmp_json["category"] = group[2];
                        rtn_groupList.push_back(tmp_json);
                    }
                    rtn_package["grouplist"] = rtn_groupList;
                   // rtn_package["grouplist_edition"] = userOperList.size();
                }
                catch (...)
                {
                    cout << "获取群聊列表错误\n";
                }
            }
            else if (rtn_signin == 2)
            {
                rtn_package["result"] = "id not found";
            }
            else if (rtn_signin == 3)
            {
                rtn_package["result"] = "password is incorrect";
            }
            else
            {
                throw -1;
            }
        }
        else
        {
            rtn_package["result"] = "Already login";
        }
    }
    catch (...)
    {
        cout << "catch error pLogin" << endl;
    }
    sendPackage(rtn_package.dump(2), 0x35, fd);
    // if(success){
    //     json rtn,rtn;
    //     rtn["userlist"]=rtn_userList;
    //     sendPackage(string(rtn.dump(4)),0x36,fd);
    //     rtn["grouplist"]=rtn_groupList;
    //     sendPackage(string(rtn.dump(4)),0x37,fd);
    // }
    // sendPackage(string(""),0x45,fd);
}

// string pLogin(string data){
//     dbClass dbC(true);
//     string rtn;
//     try{
//         json params=json::parse(data);
//         // cout<<params.dump(4);
//         // string uid=dbC.AddUser(params["name"],params["password"],"stu");
//         if(onlineUser.count(params["UID"])==0){
//             uint8_t login_result = dbC.CheckSignin(params["UID"],params["password"]);
//             switch(login_result){
//                 case 0: rtn="success"; onlineUser[params["UID"]]=time(0); break;
//                 case 2: rtn="password is incorrect";break;
//                 case 3: rtn="id not found";break;
//                 default: rtn ="server error";break;
//             }
//         }
//         else{
//             rtn="already login";
//         }
//     }
//     catch(...){
//         cout << "catch error when login !" << endl;
//     }
//     return rtn;
// }

string pGetFriendList()
{
    dbClass dbC(true);
    vector<vector<string>> cope_result = dbC.GetUserList();
    json friendList;
    for (auto user : cope_result)
    {
        json userInfo;
        userInfo["uid"] = user[0];
        userInfo["nickname"] = user[1];
        userInfo["ip"] = user[2];
        userInfo["online"] = "true";
        friendList.push_back(userInfo);
    }
    return friendList.dump(4);
}
string pGetOfflineMessage()
{
    return "Offline Message function developing";
}

void pSendMessage(int fd, json &params)
{
    if (params.is_null())
    {
        cout << "empty pamera\n";
        return;
    }
    dbClass dbC(true);
    string mid = "error";
    try
    {
        mid = dbC.SaveMessage(params["UID"], params["RID"], params["content"], "0");
    }
    catch (...)
    {
        cout << "save message error\n";
    }
    sendPackage(mid, 0x45, fd);
    return;
}
// string pSendMessage(string data){
//     string rtn;
//     dbClass dbC(true);
//     try{
//         json params=json::parse(data);
//         if(params["type"]=="text")
//             dbC.SaveMessage(params["UID"],params["RID"],params["content"]);
//         else
//             dbC.SaveMessage(params["UID"],params["RID"],"other type");
//         rtn="ok";
//     }
//     catch(...){
//         cout << "catch error when SendMessage !" << endl;
//     }
//     return rtn;
// }
void pSaveFileMessage(int fd, json &params)
{
    if (params.is_null())
    {
        cout << "empty pamera\n";
        sendPackage("", 0x38, fd);
        return;
    }
    uint16_t first_saveFile_cmd = 0x00FF; // 本来是0x00FF，但为了调试方便，改成了0100
    dbClass dbC(true);
    string messageID = dbC.SaveMessage(params["UID"], params["RID"], params["content"], "1");
    if (messageID != "-1")
    {
        userTemp[params["UID"]].save_cmd = first_saveFile_cmd;
        userTemp[params["UID"]].save_name = messageID; // + string(params["content"]);
        string filePath = "/home/userFile/" + userTemp[params["UID"]].save_name;
        cout << filePath << endl;
        userTemp[params["UID"]].f_save.open(filePath.c_str(), ios::out | ios::trunc | ios::binary);//清空后写入二进制，ios::app为追加
        sendPackage(messageID, 0x38, fd);
    }
    else
    {
        sendPackage("", 0x38, fd);
    }

    return;
}
void pSaveIcon(int fd,json& params){
    if(params.is_null()){
        cout<<"empty pamera\n";
        sendPackage("",0x3B,fd);
        return;
    }
    file_transmit_t* file_tran = &(userTemp[string(params["UID"])]);
    uint16_t first_saveFile_cmd = 0x00FF;//本来是0x00FF，但为了调试方便，改成了0100
    file_tran->save_cmd = first_saveFile_cmd;
    file_tran->save_name = string(params["UID"]);// + string(params["content"]);
    string filePath = "/home/userFile/" + file_tran->save_name;
    file_tran->f_save.open(filePath.c_str(),ios::out|ios::app);//,ios::out|ios::app);//追加写入,在原来基础上加了ios::app 
    sendPackage("",0x3B,fd);
    return;
}

void pServerSaveFile(int fd, string &data_in, uint16_t send_cmd)
{
    string uid = data_in.substr(0,6);   //取传入数据0~6字节为uid
    file_transmit_t* file_tran = &(userTemp[uid]);
    if (data_in.length() == 0)
    {
        cout << "empty pamera\n";
        sendPackage("",file_tran->save_cmd,fd);
        return;
    }
    if (file_tran->save_cmd == send_cmd)
    {
        (file_tran->f_save) << data_in.substr(6);   //取传入数据第7个字符开始（下标为6）至末尾
        sendPackage("", file_tran->save_cmd, fd);
        file_tran->save_cmd += 1;
    }
    else
    {
        cout << "file_save_shuffed" << endl;
        sendPackage("",file_tran->save_cmd,fd);
    }
    return;
}
void pEndServerSaveFile(int fd,json& params)
{
    if(params.is_null()){
        cout<<"empty pamera\n";
        sendPackage("", 0x39, fd);
        return;
    }
    file_transmit_t* file_tran = &(userTemp[string(params["UID"])]);
    try
    {
        //if(file_tran.f_save){
            file_tran->f_save.close();
        //}
    }
    catch (...)
    {
        cout << "catch error when close saved file !" << endl;
    }
    sendPackage("", 0x39, fd);
    return;
}
void pGetNextPieceFile(int fd,json& params)
{
    if(params.is_null()){
        cout<<"empty pamera\n";
        sendPackage("", 0x3a, fd);
        return;
    }
    file_transmit_t* file_tran = &(userTemp[string(params["UID"])]);
    if (file_tran->send_cmd == 0x003A)
    { // 文件发完了会把cmd置0，下次客户端传入cmd=0x0a调用本函数时判断如果cmd==0则发送传输完成的指令
        cout<<"file_send_end"<<endl;
        sendPackage("", 0x3a, fd);
        return;
    }

    bool is_finished_send = false;
    char buf_chr[1005];
    file_tran->f_send.read(&(buf_chr[0]),1000);   // 读取至多1000个字符到buf_chr中
    int real_read_length = file_tran->f_send.gcount();  //返回真的取出了多少字节，最多1000，但可能到eof不够
    if(real_read_length != 1000){
        is_finished_send = true;
    }
    string buf_str = "";
    buf_str.assign(buf_chr,real_read_length);   //将char*中real_read_length长度的字节转入buf_str
    sendPackage(buf_str, file_tran->send_cmd, fd);
    file_tran->send_cmd += 1;
    if (is_finished_send)
    {
        file_tran->send_cmd = 0x003A; // 文件发完了把cmd置0，下次客户端传入cmd=0x0a调用本函数时判断如果cmd==0则发送传输完成的指令
        file_tran->f_send.close();
    }
    return;
}
void pStartGetFile(int fd, json &params)
{
    if (params.is_null())
    {
        cout << "empty pamera\n";
        sendPackage("",0x3a,fd);
        return;
    }
    file_transmit_t* file_tran = &(userTemp[string(params["UID"])]);
    uint16_t first_sendFile_cmd = 0x0800;
    file_tran->send_cmd = first_sendFile_cmd;
    file_tran->send_name = params["MID"]; // + string(params["content"]);
    string filePath = "/home/userFile/" + file_tran->send_name;
    file_tran->f_send.open(filePath.c_str(), ios::in | ios::binary);
    if (!file_tran->f_send.is_open())
    {
        cout << "ERR:file_read_from_disk_err !!!" << endl;
        sendPackage("",0x3a,fd);
    }
    // if(!(file_tran->f_send)){//如果文件打开失败，文件不存在，返回传输结束
    //     sendPackage("",0x3a,fd);
    //     return;
    // }

    pGetNextPieceFile(fd,params);
    return;
}